/*skip start*/
/**
 * @file   worker_gen_base.hpp
 * @author wolfhead <wolfhead@wolfhead-laptop>
 * @date   Fri Jul 22 08:30:28 2011
 * 
 * @brief  this is the base of the worker_gen.hpp
 */
/*skip end*/
/*********************************************************/
/*
    functor for dynamic binding
    TEMPLATE_ARGS = WORKER_TEMPLATE_ARGS
    FUNCTION_ARGS = WORKER_FUNCTION_ARGS
    DELEGATE_PARA = WORKER_DELEGATE_PARA
*/
template<typename Ret WORKER_TEMPLATE_ARGS, typename BindType, typename ClassType>
class worker<Ret(WORKER_FUNCTION_ARGS), BindType, ClassType>
{
public:
    typedef acapella::delegate::functor
        <Ret(WORKER_FUNCTION_ARGS), BindType, ClassType> 
        functor_type;
    typedef acapella::delegate::delegate
        <Ret(WORKER_FUNCTION_ARGS), BindType, ClassType> 
        delegate_type;
    typedef acapella::shared_ptr<delegate_type> delegate_pointer_type;
    typedef acapella::shared_ptr<Task> task_pointer_type;

    worker()
    {
    }

    worker(functor_type _functor)
        :functor_(_functor)
    {
    }

    virtual ~worker()
    {
    }

    worker(const worker& _worker)
        :functor_(_worker.functor_)
    {
    }

    worker& operator= (const worker& _worker)
    {
        if (this == &_worker)
        {
            return *this;
        }
        functor_ = _worker.functor_;
        return *this;
    }

    /*skip start*/
    /** 
     * SyncCall 
     * call the functor set to the worker in synchronize mode
     * 
     * @param WORKER_FUNCTION_ARGS 
     * 
     * @return the user defined return value
     */
    /*skip end*/
    Ret SyncCall(WORKER_FUNCTION_ARGS)
    {
        delegate_pointer_type pDelegate(
            new delegate_type(functor_ WORKER_DELEGATE_PARA));

        return SyncDelegate(pDelegate);
    }

    void AsynCall(WORKER_FUNCTION_ARGS)
    {
        delegate_pointer_type pDelegate(
            new delegate_type(functor_ WORKER_DELEGATE_PARA));
        
        AsynDelegate(pDelegate);
        return;
    }

    Ret SyncDelegate(delegate_pointer_type pDelegate)
    {
        Ret returnVal;

        task_pointer_type pTask = _MakeSyncTask(pDelegate, returnVal);
        
        // schedule the task
        Schedule(pTask);

        return returnVal;        
    }

    void AsynDelegate(delegate_pointer_type pDelegate)
    {
        task_pointer_type pTask = _MakeAsynTask(pDelegate);

        // schedule the task
        Schedule(pTask);

        return;
    }

    void Schedule(task_pointer_type pTask)
    {
        _Schedule(pTask);

        pTask->wait();
    }

    void SetFunctor(const functor_type& _functor)
    {
        functor_ = _functor;
    }

    const functor_type& GetFunctor()
    {
        return functor_;
    }

protected:

    /*skip start*/
    /** 
     * _MakeSyncTask Create a Syncronize Task for worker to schedule
     * Subclass could overwrite this function to create a custom task
     * 
     * @param pDelegate pionter to the delegate which will be execute in the worker
     * @param returnRef the reference to the object wich will hold the return value
     * 
     * @return task pointer
     */
    /*skip end*/
    virtual task_pointer_type _MakeSyncTask(delegate_pointer_type pDelegate, Ret& returnRef)
    {
        return task_pointer_type(new SyncTask<
                                 delegate_type, 
                                 acapella::synchronize::_default_::semaphore
                                 >(pDelegate, returnRef));
    }

    /*skip start*/
    /** 
     * _MakeAsynTask create a Asyncronzie task for schedule
     * 
     * @param pDelegate pointer to the delegate which will be execute
     * 
     * @return task pointer
     */
    /*skip end*/
    virtual task_pointer_type _MakeAsynTask(delegate_pointer_type pDelegate)
    {
        return task_pointer_type(new AsynTask<delegate_type>(pDelegate));
    }

    /*skip start*/
    /** 
     * _Schedule this function should do the real work to make the task executed
     * 
     * @param pTask 
     */
    /*skip end*/
    virtual void _Schedule(task_pointer_type pTask) = 0;

    functor_type functor_;
};
